﻿using OnDash.Mathematics.Vector;

namespace OnDash.Mathematics.Geometry;

public struct BezierCurveQuadric(float parallel, Vector2 startAnchor, Vector2 endAnchor, Vector2 controlPoint)
{
    private Vector2 StartAnchor = startAnchor;
    private Vector2 EndAnchor = endAnchor;
    private Vector2 ControlPoint = controlPoint;
    private readonly float Parallel = parallel;

    public BezierCurveQuadric(Vector2 startAnchor, Vector2 endAnchor, Vector2 controlPoint) : this(0f, startAnchor,
        endAnchor, controlPoint)
    {
    }

    public Vector2 CalculatePoint(float t)
    {
        var r = new Vector2();
        var c = 1f - t;

        r.X = c * c * StartAnchor.X + 2 * t * c * ControlPoint.X + t * t * EndAnchor.X;
        r.Y = c * c * StartAnchor.Y + 2 * t * c * ControlPoint.Y + t * t * EndAnchor.Y;

        if (Parallel == 0f) return r;

        Vector2 perpendicular;

        if (t == 0f) perpendicular = ControlPoint - StartAnchor;
        else perpendicular = r - CalculatePointOfDerivative(t);

        return r + Vector2.Normalize(perpendicular).PerpendicularRight * Parallel;
    }

    private Vector2 CalculatePointOfDerivative(float t)
    {
        var r = new Vector2
        {
            X = (1f - t) * StartAnchor.X + t * ControlPoint.X,
            Y = (1f - t) * StartAnchor.Y + t * ControlPoint.Y
        };

        return r;
    }

    public float CalculateLength(float precision)
    {
        var length = 0f;
        var old = CalculatePoint(0f);

        for (var i = precision; i < (1f + precision); i += precision)
        {
            var n = CalculatePoint(i);
            length += (n - old).Length;
            old = n;
        }

        return length;
    }
}